/*
 * clock.c
 *
 *  Created on: Apr 3, 2011
 *      Author: Vishal Verma
 */

#include <at89c51ed2.h>  //also includes 8052.h and 8051.h
#include <mcs51reg.h>
#include <stdio.h>
#include "lcd.h"
#include "clock.h"

/*==================================GLOBALS==================================*/

static unsigned char clkMin = 0;
static unsigned char clkSec = 0;
static unsigned char clkMsec = 0;
unsigned char clkOn = FALSE;
unsigned char clkEMode = FALSE;

/*============================FUNCTION DEFINITIONS===========================*/

/*
* NAME :            clkToggle
*
* DESCRIPTION :     Wrapper to toggle clock flag
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	clkOn
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void clkToggle() {
	(clkOn == TRUE) ? (clkOn = FALSE) : (clkOn = TRUE);
}

/*
* NAME :            clkReset
*
* DESCRIPTION :     Reset the clock to 00:00:00
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	clkMin, clkSec, clkMsec
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void clkReset() {
		clkMin = 0;
		clkSec = 0;
		clkMsec = 0;
		dispUpdate(0,0,0,1);
}

/*
* NAME :            dispUpdate
*
* DESCRIPTION :     Update LCD display
*
* INPUTS :
*       PARAMETERS:	min, sec, msec, all
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	clkMin, clkSec, clkMsec
*       RETURN :	
*
* PROCESS :
*                   [1]  Save state - clock running or not
*					[2]	 Depending on parameters passed 0/1, update fixed sections of the LCD
*
* NOTES :           Pass parameter as 1 if you want to update that sectioon. Parameter 'all' is overriding.
*/

void dispUpdate(int min, int sec, int msec, int all) {

	unsigned char state = 0;

	if (clkOn == FALSE) {
		state = FALSE;
	}
	else {
		clkOn = FALSE;
		state = TRUE;
	}

	if (clkEMode == TRUE) {
		lcdgotoaddr(CLK_MIN);
		if (min || all) {
			lcdputch(((clkMin%100)/10)+ASCIIBASE);
			lcdputch((clkMin%10)+ASCIIBASE);
			lcdputch(':');
		}
		lcdgotoaddr(CLK_EM_SEC);
		if (sec || all) {
			lcdputch(((clkSec%100)/10)+ASCIIBASE);
			lcdputch((clkSec%10)+ASCIIBASE);
			lcdputch('.');
		}
		lcdgotoaddr(CLK_EM_MSEC);
		if (msec || all) {
			lcdputch(((clkMsec%100)/10)+ASCIIBASE);
			lcdputch((clkMsec%10)+ASCIIBASE);
		}
	}
	else {
		lcdgotoaddr(CLK_MIN);
		lcdputch(' ');						//put space to remove earlier char if any
		if (min || all) {
			lcdputch(((clkMin%100)/10)+ASCIIBASE);
			lcdputch((clkMin%10)+ASCIIBASE);
			lcdputch(':');
		}
		lcdgotoaddr(CLK_SEC);
		if (sec || all) {
			lcdputch(((clkSec%100)/10)+ASCIIBASE);
			lcdputch((clkSec%10)+ASCIIBASE);
			lcdputch('.');
		}
		lcdgotoaddr(CLK_MSEC);
		if (msec || all) {
			lcdputch((clkMsec%10)+ASCIIBASE);
		}
	}

	clkOn = state;
}

/*
* NAME :            emToggle
*
* DESCRIPTION :     Toggle enhanced mode - 100th of a second accuracy
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  turns on flag and calls dispUpdate
*
* NOTES :           
*/

void emToggle() {

	unsigned char state = 0;

	if (clkOn == FALSE) {
		state = FALSE;
	}
	else {
		clkOn = FALSE;
		state = TRUE;
	}

	(clkEMode == TRUE) ? (clkEMode = FALSE) : (clkEMode = TRUE);
	dispUpdate(0,0,0,1);

	clkOn = state;
}

/*
* NAME :            clkInit
*
* DESCRIPTION :     Initialize 8051 registers for clock display
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void clkInit(void) {

	clkOn = FALSE;

	IE=0x00;									//Disable Interrupts
	ET1 = TRUE;

	TMOD = TMOD | 0x10;
	TF1=FALSE;

	TH1 = 0xDC;									//Load Timer (10ms) - Calculations presented with writeup
	TL1 = 0x25;
	TR1=TRUE;									//start timer
}

/*
* NAME :            timerIsr
*
* DESCRIPTION :     ISR which will be called when 10 ms timer overflows
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	clkMin, clkSec, clkMsec
*       RETURN :	
*
* PROCESS :
*                   [1]  Increment mSec and update msec display each time
*					[2]	 If msec overflowed, change seconds and update display for sec and msec
*					[3]	 If sec overflowed, change minutes and update display for min, sec and msec
*
* NOTES :           
*/

void timerIsr(void) {

	static unsigned char clkTenDiv = 0; //divide by 10 for non-enhanced mode

	TH1 = 0xDC;							//Reload Timer
	TL1 = 0x25;
	TR1=1;                          	//Start timer

	if(clkOn == TRUE) {

		if(clkEMode == TRUE) {

			clkMsec++;
			if(clkMsec >= 100) {
				clkMsec = 0;
				clkSec++;

				if(clkSec >= 60) {
					clkSec = 0;
					clkMin++;
					dispUpdate(1,1,1,0);
				}
				else {
					dispUpdate(0,1,1,0);
				}
			}
			else {
				P1_6 = clkMsec%2;		//Instrumentation to enable measurement on port pin
				dispUpdate(0,0,1,0);
			}

		}
		else {
			clkTenDiv++;
			if(clkTenDiv == 10) {
				clkMsec++;
				clkTenDiv=0;
			}
			if(clkMsec >= 10) {
				clkMsec = 0;
				clkSec++;

				if(clkSec >= 60) {
					clkSec = 0;
					clkMin++;
					dispUpdate(1,1,1,0);
				}
				else {
					dispUpdate(0,1,1,0);
				}
			}
			else {
				P1_4 = clkMsec%2;
				dispUpdate(0,0,1,0);
			}
		}
	}
}
